package com.shop.shop_end.handle;
import cn.hutool.core.util.StrUtil;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.shop.shop_end.config.AuthAccess;
import com.shop.shop_end.entity.Admin;
import com.shop.shop_end.entity.User;
import com.shop.shop_end.exception.ServiceException;
import com.shop.shop_end.service.AdminService;
import com.shop.shop_end.service.UserService;
import com.shop.shop_end.utils.TokenUtils;
import com.shop.shop_end.variable.ErrorCodeEnum;
import com.shop.shop_end.variable.RoleVariable;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.net.URLEncoder;
import java.util.List;


/**
 * 登录检查
 * 以下是判断session里是否有用户信息来进行判断拦截
 * 1.配置到拦截器要拦截哪些请求
 * 2.把这些配置放在容器中
 *
 * 实现HandlerInterceptor接口
 */
//@Slf4j
//public class LoginInterceptor implements HandlerInterceptor {
//
//    @Autowired
//    private UserMapper userMapper;
//
//    /**
//     * 目标方法执行之前
//     * 登录检查写在这里，如果没有登录，就不执行目标方法
//     * @param request
//     * @param response
//     * @param handler
//     * @return
//     * @throws Exception
//     */
//    @Override
//    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//        String requestURI = request.getRequestURI();
//        log.info("preHandle拦截的请求路径是{}",requestURI);
//        //如果不是映射到方法直接通过
//        if (handler instanceof HandlerMethod){
//            AuthAccess annotation = ((HandlerMethod) handler).getMethodAnnotation(AuthAccess.class);
//            if (annotation != null){
//                return true;
//            }
//        }
//        //执行认证
//        HttpSession session = request.getSession();
//        UserVo loginUser = (UserVo) session.getAttribute("userInfo");
//        System.out.println("user==>"+ loginUser);
//        if(loginUser != null){
//            return true;
//        }
//        else {
//            //拦截住。未登录。跳转到登录页
//            request.setAttribute("error","请先登录");
//            request.getRequestDispatcher("/ce/login").forward(request,response);
//            return false;
//        }
//    }
//}




//下面是使用token验证的方法，有点问题
/**
 * 登录检查
 * 1.配置到拦截器要拦截哪些请求
 * 2.把这些配置放在容器中
 *
 * 实现HandlerInterceptor接口
 */
@Slf4j
@Component
public class LoginInterceptor implements HandlerInterceptor {
    final Logger logger = LoggerFactory.getLogger(LoginInterceptor.class);

    @Resource
    private UserService userService;

    @Resource
    private AdminService adminService;

    /**
     * 目标方法执行之前
     * 登录检查写在这里，如果没有登录，就不执行目标方法
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String token = request.getHeader("token");//获取请求头token
        String requestURI = request.getRequestURI();
        logger.info("preHandle拦截的请求路径是{}",requestURI);
        String value = URLEncoder.encode("请先登录", "UTF-8");
        String redirectUrl = "/user/loginPage?error=" + value;
//        response.setStatus(HttpServletResponse.SC_FOUND); // 设置HTTP状态码为302，表示临时重定向
        if (StrUtil.isBlank(token)){//如果请求头的token为空
            //查看url里是否有token
            token = request.getParameter("token");
        }
        logger.info("token==>{}", token);
        //如果不是映射到方法直接通过
        if (handler instanceof HandlerMethod){
            AuthAccess annotation = ((HandlerMethod) handler).getMethodAnnotation(AuthAccess.class);
            if (annotation != null){
                return true;
            }
        }
        //执行认证
        //token还是为空，那就是没有，进行拦截
        if (StrUtil.isBlank(token)){
            response.setHeader("Location", redirectUrl); // 设置Location头
            throw new ServiceException(ErrorCodeEnum.NO_TOKEN, "请先登录");
        }
        //获取token里的userId和角色
        String id;
        String role;
        String password;
        User user = new User();
        Admin admin = new Admin();
        try{
            List<String> currentUserInfo = TokenUtils.getCurrentUserInfo(token);
            id = currentUserInfo.get(0);
            role = currentUserInfo.get(1);
            logger.info("id==>{}, role==>{}", id, role);
        }catch (JWTDecodeException j){
            response.setHeader("Location", redirectUrl); // 设置Location头
            throw new ServiceException(ErrorCodeEnum.NO_TOKEN, "请先登录");
        }
        //根据token中的userId查询数据库
        if (role.equals(RoleVariable.ROLE_ADMIN)){
            admin = adminService.getAdminById(Long.valueOf(id));
            password = admin.getPassword();
            request.getSession().setAttribute("admin", admin);
        }else if (role.equals(RoleVariable.ROLE_USER)){
            user = userService.getUserById(Long.valueOf((id)));
            password = user.getPassword();
            request.getSession().setAttribute("user", user);
        }else {
            throw new ServiceException(ErrorCodeEnum.PARAMS_ERROR, "无此角色==》" + role);
        }
        if (user == null && admin == null){
            response.setHeader("Location", redirectUrl); // 设置Location头
            throw new ServiceException(ErrorCodeEnum.NO_TOKEN, "请先登录");
        }

        //用户名密码加密
        JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(password)).build();
        try {
            jwtVerifier.verify(token);//验证token
        }catch (JWTVerificationException e){
            response.setHeader("Location", redirectUrl); // 设置Location头
            throw new ServiceException(ErrorCodeEnum.NO_TOKEN, "请先登录");
        }
        return true;
    }
}
